Membuat output PaliGemma dengan Keras

Lihat di ai.google.dev Jalankan di Google Colab Lihat sumber di GitHub

Model PaliGemma memiliki kemampuan multimodal, yang memungkinkan Anda menghasilkan output menggunakan data input teks dan gambar. Anda dapat menggunakan data gambar dengan model ini untuk memberikan konteks tambahan untuk permintaan Anda, atau menggunakan model untuk menganalisis konten gambar. Tutorial ini menunjukkan cara menggunakan PaliGemma dengan Keras agar dapat menganalisis gambar dan menjawab pertanyaan tentang gambar tersebut.

Isi notebook ini

Notebook ini menggunakan PaliGemma dengan Keras dan menunjukkan cara:

  • Menginstal Keras dan dependensi yang diperlukan
  • Download PaliGemmaCausalLM, varian PaliGemma terlatih untuk pemodelan bahasa visual kausal, dan gunakan untuk membuat model
  • Menguji kemampuan model untuk menyimpulkan informasi tentang gambar yang diberikan

Sebelum memulai

Sebelum membaca notebook ini, Anda harus memahami kode Python, serta cara melatih model bahasa besar (LLM). Anda tidak perlu memahami Keras, tetapi pengetahuan dasar tentang Keras akan membantu saat membaca kode contoh.

Penyiapan

Bagian berikut menjelaskan langkah-langkah awal untuk membuat notebook menggunakan model PaliGemma, termasuk akses model, mendapatkan kunci API, dan mengonfigurasi runtime notebook.

Mendapatkan akses ke PaliGemma

Sebelum menggunakan PaliGemma untuk pertama kalinya, Anda harus meminta akses ke model melalui Kaggle dengan menyelesaikan langkah-langkah berikut:

  1. Login ke Kaggle, atau buat akun Kaggle baru jika Anda belum memilikinya.
  2. Buka kartu model PaliGemma, lalu klik Minta Akses.
  3. Lengkapi formulir izin dan setujui persyaratan dan ketentuan.

Mengonfigurasi kunci API

Untuk menggunakan PaliGemma, Anda harus memberikan nama pengguna Kaggle dan kunci API Kaggle.

Untuk membuat kunci API Kaggle, buka halaman Setelan di Kaggle, lalu klik Buat Token Baru. Tindakan ini akan memicu download file kaggle.json yang berisi kredensial API Anda.

Kemudian, di Colab, pilih Secrets (🔑) di panel kiri dan tambahkan nama pengguna Kaggle dan kunci Kaggle API Anda. Simpan nama pengguna Anda dengan nama KAGGLE_USERNAME dan kunci API Anda dengan nama KAGGLE_KEY.

Memilih runtime

Untuk menyelesaikan tutorial ini, Anda harus memiliki runtime Colab dengan resource yang memadai untuk menjalankan model PaliGemma. Dalam hal ini, Anda dapat menggunakan GPU T4:

  1. Di kanan atas jendela Colab, klik menu dropdown ▾ (Opsi koneksi tambahan).
  2. Pilih Change runtime type.
  3. Di bagian Hardware accelerator, pilih T4 GPU.

Menetapkan variabel lingkungan

Tetapkan variabel lingkungan untuk KAGGLE_USERNAME, KAGGLE_KEY, dan KERAS_BACKEND.

import os
from google.colab import userdata

# Set up environmental variables
os.environ["KAGGLE_USERNAME"] = userdata.get('KAGGLE_USERNAME')
os.environ["KAGGLE_KEY"] = userdata.get('KAGGLE_KEY')
os.environ["KERAS_BACKEND"] = "jax"

Menginstal Keras

Jalankan sel di bawah untuk menginstal Keras.

pip install -U -q keras-nlp keras-hub kagglehub

Mengimpor dependensi dan mengonfigurasi Keras

Instal dependensi yang diperlukan untuk notebook ini dan konfigurasikan backend Keras. Anda juga akan menetapkan Keras untuk menggunakan bfloat16 sehingga framework menggunakan lebih sedikit memori.

import keras
import keras_hub
import numpy as np
import PIL
import requests
import io
import matplotlib
import re
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from PIL import Image

keras.config.set_floatx("bfloat16")

Memuat model

Setelah menyiapkan semuanya, Anda dapat mendownload model terlatih dan membuat beberapa metode utilitas untuk membantu model menghasilkan responsnya. Pada langkah ini, Anda akan mendownload model menggunakan PaliGemmaCausalLM dari Keras Hub. Class ini membantu Anda mengelola dan menjalankan struktur model bahasa visual kausal PaliGemma. Model bahasa visual kausal memprediksi token berikutnya berdasarkan token sebelumnya. Keras Hub menyediakan implementasi dari banyak arsitektur model populer.

Buat model menggunakan metode from_preset dan cetak ringkasannya. Proses ini akan memerlukan waktu sekitar satu menit.

paligemma = keras_hub.models.PaliGemmaCausalLM.from_preset("kaggle://keras/paligemma2/keras/pali_gemma2_mix_3b_224")
paligemma.summary()

Membuat metode utilitas

Untuk membantu Anda membuat respons dari model, buat dua metode utilitas:

  • crop_and_resize: Metode helper untuk read_img. Metode ini memangkas dan mengubah ukuran gambar ke ukuran yang diteruskan sehingga gambar akhir diubah ukurannya tanpa mendistorsi proporsi gambar.
  • read_img: Metode helper untuk read_img_from_url. Metode ini adalah yang benar-benar membuka gambar, mengubah ukurannya agar sesuai dengan batasan model, dan memasukkannya ke dalam array yang dapat ditafsirkan oleh model.
  • read_img_from_url: Mengambil gambar melalui URL yang valid. Anda memerlukan metode ini untuk meneruskan gambar ke model.

Anda akan menggunakan read_img_from_url di langkah berikutnya dari notebook ini.

def crop_and_resize(image, target_size):
    width, height = image.size
    source_size = min(image.size)
    left = width // 2 - source_size // 2
    top = height // 2 - source_size // 2
    right, bottom = left + source_size, top + source_size
    return image.resize(target_size, box=(left, top, right, bottom))

def read_image(url, target_size):
    contents = io.BytesIO(requests.get(url).content)
    image = PIL.Image.open(contents)
    image = crop_and_resize(image, target_size)
    image = np.array(image)
    # Remove alpha channel if necessary.
    if image.shape[2] == 4:
        image = image[:, :, :3]
    return image

def parse_bbox_and_labels(detokenized_output: str):
  matches = re.finditer(
      '<loc(?P<y0>\d\d\d\d)><loc(?P<x0>\d\d\d\d)><loc(?P<y1>\d\d\d\d)><loc(?P<x1>\d\d\d\d)>'
      ' (?P<label>.+?)( ;|$)',
      detokenized_output,
  )
  labels, boxes = [], []
  fmt = lambda x: float(x) / 1024.0
  for m in matches:
    d = m.groupdict()
    boxes.append([fmt(d['y0']), fmt(d['x0']), fmt(d['y1']), fmt(d['x1'])])
    labels.append(d['label'])
  return np.array(boxes), np.array(labels)

def display_boxes(image, boxes, labels, target_image_size):
  h, l = target_size
  fig, ax = plt.subplots()
  ax.imshow(image)
  for i in range(boxes.shape[0]):
      y, x, y2, x2 = (boxes[i]*h)
      width = x2 - x
      height = y2 - y
      # Create a Rectangle patch
      rect = patches.Rectangle((x, y),
                               width,
                               height,
                               linewidth=1,
                               edgecolor='r',
                               facecolor='none')
      # Add label
      plt.text(x, y, labels[i], color='red', fontsize=12)
      # Add the patch to the Axes
      ax.add_patch(rect)

  plt.show()

def display_segment_output(image, bounding_box, segment_mask, target_image_size):
    # Initialize a full mask with the target size
    full_mask = np.zeros(target_image_size, dtype=np.uint8)
    target_width, target_height = target_image_size

    for bbox, mask in zip(bounding_box, segment_mask):
        y1, x1, y2, x2 = bbox
        x1 = int(x1 * target_width)
        y1 = int(y1 * target_height)
        x2 = int(x2 * target_width)
        y2 = int(y2 * target_height)

        # Ensure mask is 2D before converting to Image
        if mask.ndim == 3:
            mask = mask.squeeze(axis=-1)
        mask = Image.fromarray(mask)
        mask = mask.resize((x2 - x1, y2 - y1), resample=Image.NEAREST)
        mask = np.array(mask)
        binary_mask = (mask > 0.5).astype(np.uint8)


        # Place the binary mask onto the full mask
        full_mask[y1:y2, x1:x2] = np.maximum(full_mask[y1:y2, x1:x2], binary_mask)
    cmap = plt.get_cmap('jet')
    colored_mask = cmap(full_mask / 1.0)
    colored_mask = (colored_mask[:, :, :3] * 255).astype(np.uint8)
    if isinstance(image, Image.Image):
        image = np.array(image)
    blended_image = image.copy()
    mask_indices = full_mask > 0
    alpha = 0.5

    for c in range(3):
        blended_image[:, :, c] = np.where(mask_indices,
                                          (1 - alpha) * image[:, :, c] + alpha * colored_mask[:, :, c],
                                          image[:, :, c])

    fig, ax = plt.subplots()
    ax.imshow(blended_image)
    plt.show()

Membuat output

Setelah memuat model dan membuat metode utilitas, Anda dapat meminta model dengan data gambar dan teks untuk menghasilkan respons. Model PaliGemma dilatih dengan sintaksis perintah tertentu untuk tugas tertentu, seperti answer, caption, dan detect. Untuk informasi selengkapnya tentang sintaksis tugas perintah PaliGemma, lihat Perintah dan petunjuk sistem PaliGemma.

Siapkan gambar untuk digunakan dalam perintah pembuatan dengan menggunakan kode berikut untuk memuat gambar pengujian ke dalam objek:

target_size = (224, 224)
image_url = 'https://storage.googleapis.com/keras-cv/models/paligemma/cow_beach_1.png'
cow_image = read_image(image_url, target_size)
matplotlib.pyplot.imshow(cow_image)

Menjawab dalam bahasa tertentu

Kode contoh berikut menunjukkan cara meminta model PaliGemma untuk mendapatkan informasi tentang objek yang muncul dalam gambar yang diberikan. Contoh ini menggunakan sintaksis answer {lang} dan menampilkan pertanyaan tambahan dalam bahasa lain:

prompt = 'answer en where is the cow standing?\n'
# prompt = 'svar no hvor står kuen?\n'
# prompt = 'answer fr quelle couleur est le ciel?\n'
# prompt = 'responda pt qual a cor do animal?\n'

output = paligemma.generate(
    inputs={
        "images": cow_image,
        "prompts": prompt,
    }
)
print(output)

Menggunakan perintah detect

Contoh kode berikut menggunakan sintaksis perintah detect untuk menemukan objek dalam gambar yang disediakan. Kode ini menggunakan fungsi parse_bbox_and_labels() dan display_boxes() yang ditentukan sebelumnya untuk menafsirkan output model dan menampilkan kotak pembatas yang dihasilkan.

prompt = 'detect cow\n'
output = paligemma.generate(
    inputs={
        "images": cow_image,
        "prompts": prompt,
    }
)
boxes, labels = parse_bbox_and_labels(output)
display_boxes(cow_image, boxes, labels, target_size)

Menggunakan perintah segment

Contoh kode berikut menggunakan sintaksis perintah segment untuk menemukan area gambar yang ditempati oleh objek. Fungsi ini menggunakan library big_vision Google untuk menafsirkan output model dan membuat mask untuk objek yang tersegmentasi.

Sebelum memulai, instal library big_vision dan dependensinya, seperti yang ditunjukkan dalam contoh kode ini:

import os
import sys

# TPUs with
if "COLAB_TPU_ADDR" in os.environ:
  raise "It seems you are using Colab with remote TPUs which is not supported."

# Fetch big_vision repository if python doesn't know about it and install
# dependencies needed for this notebook.
if not os.path.exists("big_vision_repo"):
  !git clone --quiet --branch=main --depth=1 \
     https://github.com/google-research/big_vision big_vision_repo

# Append big_vision code to python import path
if "big_vision_repo" not in sys.path:
  sys.path.append("big_vision_repo")


# Install missing dependencies. Assume jax~=0.4.25 with GPU available.
!pip3 install -q "overrides" "ml_collections" "einops~=0.7" "sentencepiece"

Untuk contoh segmentasi ini, muat dan siapkan gambar lain yang menyertakan kucing.

cat = read_image('https://big-vision-paligemma.hf.space/file=examples/barsik.jpg', target_size)
matplotlib.pyplot.imshow(cat)

Berikut adalah fungsi untuk membantu mengurai output segmen dari PaliGemma

import  big_vision.evaluators.proj.paligemma.transfers.segmentation as segeval
reconstruct_masks = segeval.get_reconstruct_masks('oi')
def parse_segments(detokenized_output: str) -> tuple[np.ndarray, np.ndarray]:
  matches = re.finditer(
      '<loc(?P<y0>\d\d\d\d)><loc(?P<x0>\d\d\d\d)><loc(?P<y1>\d\d\d\d)><loc(?P<x1>\d\d\d\d)>'
      + ''.join(f'<seg(?P<s{i}>\d\d\d)>' for i in range(16)),
      detokenized_output,
  )
  boxes, segs = [], []
  fmt_box = lambda x: float(x) / 1024.0
  for m in matches:
    d = m.groupdict()
    boxes.append([fmt_box(d['y0']), fmt_box(d['x0']), fmt_box(d['y1']), fmt_box(d['x1'])])
    segs.append([int(d[f's{i}']) for i in range(16)])
  return np.array(boxes), np.array(reconstruct_masks(np.array(segs)))

Membuat kueri PaliGemma untuk menyegmentasikan kucing dalam gambar

prompt = 'segment cat\n'
output = paligemma.generate(
    inputs={
        "images": cat,
        "prompts": prompt,
    }
)

Memvisualisasikan mask yang dihasilkan dari PaliGemma

bboxes, seg_masks = parse_segments(output)
display_segment_output(cat, bboxes, seg_masks, target_size)

Perintah batch

Anda dapat memberikan lebih dari satu perintah perintah dalam satu perintah sebagai batch petunjuk. Contoh berikut menunjukkan cara menyusun teks perintah untuk memberikan beberapa petunjuk.

prompts = [
    'answer en where is the cow standing?\n',
    'answer en what color is the cow?\n',
    'describe en\n',
    'detect cow\n',
    'segment cow\n',
]
images = [cow_image, cow_image, cow_image, cow_image, cow_image]
outputs = paligemma.generate(
    inputs={
        "images": images,
        "prompts": prompts,
    }
)
for output in outputs:
    print(output)